#include "../head.h"
/*
建立套接字 scocket   返回sockfd
int socket(int domain, int type, int protocol);
    domain 网络协议 AF_INET    AF_INET6
    type  SOCK_STREAM 选择TCP   SOCK_DGRAM 选择UDP

绑定自己的IP地址  和 端口号   0、-1
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    sockfd  套接字描述符
    addr    结构体sockaddr的指针 ip和端口
    addrlen  结构体的大小

listen()声明sockfd处于监听状态  0、-1
int listen(int sockfd, int backlog);
    sockfd ： 套接字文件描述符
    backlog  ：同时  最多支持连接上来的客户端总数


等待接受客户端连接  失败-1  返回已连接的套接字文件描述符
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    sockfd： 套接字文件描述符
    addr  ：  连接上来的客户端的IP地址和端口号
    addrlen ： 长度

接收数据  失败-1  返回0 表示客户端断开连接
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    sockfd： 已连接的套接字文件描述符  connectfd
    buf  ： 接收到的数据存储到这里
    len  ：  接收数据的大小
    flags  ：  一般设置为  0
*/

int main()
{
    // 创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket error");
        return -1;
    }
    printf("socket ok...\n");

    // 创建Server端地址结构体
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;                        // 使用ipv4
    addr.sin_port = htons(4096);                     // 端口   htons()  主机字节序转网络字节序host to net
    addr.sin_addr.s_addr = inet_addr("192.168.47.198"); // ip  inet_addr() 将主机IP 转成 网络IP

    // 绑定
    int bind_res = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (bind_res < 0)
    {
        perror("bind error");
        return -1;
    }
    printf("bind ok...\n");

    // 监听
    int listen_res = listen(sockfd, 10);
    if (listen_res < 0)
    {
        perror("listen error");
        return -1;
    }
    printf("listen ok...\n");

    while (1)
    {
        printf("waiting...\n");

        // 创建Client端地址结构体
        struct sockaddr_in ClientAddr;
        memset(&addr, 0, sizeof(addr));

        // 接受客户端连接  返回已连接的套接字文件描述符
        int ClientAddr_len = sizeof(ClientAddr);
        int connectfd = accept(sockfd, (struct sockaddr *)&ClientAddr, &ClientAddr_len);
        if (connectfd < 0)
        {
            perror("accept error");
            continue;
        }
        printf("Client Connected! ip: %s, port: %d\n", inet_ntoa(ClientAddr.sin_addr), ntohs(ClientAddr.sin_port));

        while (1)
        {
            // 接收数据
            char buf[1024] = {0};
            // recv() 一定用的是 connectfd
            ssize_t recv_res = recv(connectfd, buf, sizeof(buf), 0);
            if (recv_res < 0)
            {
                perror("recv error");
                continue;
            }
            if (recv_res == 0)
            {
                printf("client closed...\n");
                break;
            }

            printf("recv: %s\n", buf);
        }
        // 关闭已连接的套接字文件描述符
        close(connectfd);
        printf("server side close connectfd\n");
    }

    return 0;
}

// https://newstar.wiki/learn/nc  tcp调试工具
// 模拟客户端  nc 192.168.46.2 11111